#include "smallc.h"
ifstream codein;                                // 代码文件

ofstream errout;                                // 错误输出文件

vector<string> code;                            // 代码

int linenum;                                    // 当前处理到的行号
int charnum;                                    // 当前处理到的字符下标
int number;                                     // 当前数字
int txind;                                      // 当前符号表大小
int parnum;                                     // 当前函数参数个数
int lvarnum;                                    // 当前函数局部变量个数
int pcnum;                                      // 当前pcode个数
int dastack[datamaxn];

string proname;                                 // 当前标识符所属函数
string linecode;                                // 当前代码行
string id;                                      // 当前ident
string em[errormax];                            // 错误信息

map<string,symbol> word;                        // 保留字

instruction Pcode[pcodemax];                    // pcode

char ch;                                        // 最近一次从文件中读出的字符

symbol sym;                                     // 当前符号类型
symbol rwordsym[rwordnum];                      // 保留字对应的符号类型

tablestruct table[txmax];                       // 符号表

/*
* 编译器初始化
*/
void init(){
    linenum=0;
    charnum=0; 
    ch=' ';
    txind=0;
    pcnum=0;

    word["if"]=ifsym;
    word["else"]=elsesym;
    word["int"]=intsym;
    word["read"]=readsym;
    word["write"]=writesym;
    word["const"]=constsym;
    word["return"]=returnsym;
    word["while"]=whilesym;
    word["case"]=casesym;
    word["switch"]=switchsym;

    em[0]="缺少分号";
    em[1]="常数超过指定位数";
    em[2]="缺少变量类型";
    em[3]="保留字不能作为标识符";
    em[4]="重复声明";
    em[5]="缺少赋值符号";
    em[6]="缺少常量";
    em[7]="缺少分号";
    em[8]="缺少左括号";
    em[9]="缺少右括号";
    em[10]="缺少左花括号";
    em[11]="缺少标识符";
    em[12]="未定义的标识符";
    em[13]="不能对const变量赋值";
    em[14]="不能对函数赋值";
    em[15]="缺少右花括号";
    em[16]="必须写入int";
    em[17]="必须输出有效变量";
    em[18]="switch缺少参数";

    em[1000]="无法识别";
}



/*
* 从文件中读取一个字符
*/
void getch(){
    if(charnum==linecode.size()&&linenum<code.size()-1){
        linecode=code[++linenum];
        charnum=0;
    }
    if(charnum==linecode.size()&&linenum==code.size()-1) ch=0;
    else ch=linecode[charnum++];
}

/*
* 从文件中读取一个单词
*/
void getsym(){
    while(ch==' '||ch=='\n'||ch=='\t') getch();
    if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){
        id="";
        do{
            id+=ch;
            getch();
        }while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9'));
        if(word.count(id)==0){                  // 当前的单词是标识符
            sym=identsym;
        }
        else{
            sym=word[id];
        }
    }
    else if(ch>='0'&&ch<='9'){
        int len=0;
        number=0;
        do{
            len++;
            number=number*10+ch-'0';
            getch();
        }while(ch>='0'&&ch<='9');
        sym=numbersym;
        if(len>nummaxlen) error(1);
    }
    else if(ch=='+'){
        sym=plussym;
        getch();
    }
    else if(ch=='-'){
        sym=minussym;
        getch();
    }
    else if(ch=='*'){
        sym=mulsym;
        getch();
    }
    else if(ch=='/'){
        getch();
        if(ch!='*') sym=divsym;
        else{
            while(true){
                do{
                    getch();
                }while(ch!='*');
                getch();
                if(ch=='/'){
                    getch();
                    getsym();
                }
            }
        }
    }
    else if(ch=='('){
        sym=lparensym;
        getch();
    }
    else if(ch==')'){
        sym=rparensym;
        getch();
    }
    else if(ch==';'){
        sym=semicolonsym;
        getch();
    }
    else if(ch=='='){
        getch();
        if(ch=='='){
            sym=eqlsym;
            getch();
        }
        else sym=becomesym;
    }
    else if(ch=='<'){
        getch();
        if(ch=='='){
            sym=leqsym;
            getch();
        }
        else sym=ltsym;
    }
    else if(ch=='>'){
        getch();
        if(ch=='='){
            sym=geqsym;
            getch();
        }
        else sym=gtsym;
    }
    else if(ch=='{'){
        sym=beginsym;
        getch();
    }
    else if(ch=='}'){
        sym=endsym;
        getch();
    }
    else if(ch==','){
        sym=commasym;
        getch();
    }
    else if(ch=='%'){
        sym=modsym;
        getch();
    }
    else if(ch=='!'){
        getch();
        if(ch=='='){
            sym=neqsym;
            getch();
        }
        else sym=nulsym;
    }
    else{
        sym=nulsym;
        getch();
    }
}

/*
* 错误处理
* 
* errorid 错误码
*/
void error(int errorid){
    cout<<"error "<<linenum+1<<"行: "<<em[errorid]<<endl;
}

/*
* 检查标识符的有效性
*
* kind 标识符类型
* level 所属等级
*/
bool isvaliddeclaration(object kind){
    for(int i=0;i<txind;i++){
        if(kind==constant&&table[i].kind==constant&&id==table[i].name) return false;
        if(kind==procedure){
            if(table[i].kind==procedure&&id==table[i].name) return false;
            if(table[i].kind==constant&&id==table[i].name) return false;
        }
        if(kind==variable){
            if(table[i].kind==procedure&&id==table[i].name) return false;
            if(table[i].kind==variable&&id==table[i].name&&table[i].proname==proname) return false;
        }
    }
    return true;
}

/*
* 填充符号表
*
* name      名字
* kind      类型 const var procedure
* adr       地址 仅const不使用
* par       参数数量 仅procedure使用
* lvar      局部变量 仅procedure使用
* proname   所属函数 仅var使用
*/
void enter(object kind){
    if(kind==constant){
        table[txind].name=id;
        table[txind].kind=kind;
        table[txind].val=number;
    }
    else if(kind==procedure){
        table[txind].adr=pcnum;
        table[txind].name=id;
        table[txind].kind=kind;
    }
    else{
        table[txind].name=id;
        table[txind].kind=kind;
        table[txind].proname=proname;
        table[txind].adr=parnum+lvarnum;
    }
    txind++;
    ptable();
}
    
/*
* 回填符号表
*/
void renter(){
    for(int i=txind-1;i>=0;i--){
        if(table[i].kind==procedure){
            table[i].par=parnum;
            table[i].lvar=lvarnum;
            ptable();
            break;
        }
    }
    
}

/*
* 处理const声明
*/
void constdeclaration(){
    getsym();
    if(word.count(id)==0){
        if(isvaliddeclaration(constant)){
            getsym();
            if(sym==becomesym){
                getsym();
                if(sym==numbersym){
                    enter(constant);
                    getsym();
                    if(sym==commasym) constdeclaration();
                    else if(sym==semicolonsym) getsym();
                    else error(7);
                }
                else error(6);
            }
            else error(5);
        }
        else error(4);
    }
    else error(3);
}

/*
* 处理参数声明
*/
void parameterdeclaration(){
    if(sym==intsym){
        getsym();
        if(sym==identsym){
            if(word.count(id)==0){
                parnum++;
                enter(variable);
                getsym();
                while(sym==commasym){
                    getsym();
                    parameterdeclaration();
                }
            }
            else error(3);
        }
        else error(11);
    }
    else error(2);
}

/*
* 处理int声明
*/
void intdeclaration(){
    if(sym==identsym){
        if(word.count(id)==0){
            if(isvaliddeclaration(variable)){
                lvarnum++;
                enter(variable);
                getsym();
                while(sym==commasym){
                    getsym();
                    intdeclaration();
                }
            }
            else error(4);
        }
        else error(3);
    }
    else error(11);
}

/*
* 查找当前标识符在符号表中的位置
*/
int findintable(string name){
    for(int i=txind-1;i>=0;i--){
        if(table[i].name==name){
            if(table[i].kind==constant) return i;
            else if(table[i].kind==procedure) return i;
            else{
                if(table[i].proname==proname) return i;
            }
        }
    }
    return -1;
}

/*
* 处理因子
*/
void factor(){
    if(sym==identsym){
        int t=findintable(id);
        if(t!=-1){
            if(table[t].kind==constant){
                gen(LIT,table[t].val);
                getsym();
            } 
            else if(table[t].kind==variable){
                gen(LOD,table[t].adr);
                getsym();
            }
            else{
                getsym();
                if(sym==lparensym){
                    getsym();
                    if(sym!=rparensym){
                        expression();
                        while(sym==commasym){
                            getsym();
                            expression();
                        }
                        if(sym==rparensym) getsym();
                        else error(9);
                    }
                    gen(STP,table[t].par);
                    gen(CAL,table[t].adr);
                }
                else error(8);
            }
        }
        else error(12);
    }
    else if(sym==numbersym){
        gen(LIT,number);
        getsym();
    }
    else if(sym==lparensym){
        getsym();
        expression();
        if(sym==rparensym) getsym();
        else error(9);
    }

}

/*
* 处理项
*/
void term(){
    factor();
    while(sym==mulsym||sym==divsym||sym==modsym){
        if(sym==mulsym){
            getsym();
            factor();
            gen(OPR,4);
        }
        else if(sym==divsym){
            getsym();
            factor();
            gen(OPR,5);
        }
        else if(sym==modsym){
            getsym();
            factor();
            gen(OPR,1);
        }
    }
}

/*
* 处理表达式
*/
void expression(){
    if(sym==minussym){
        gen(LIT,0);
        getsym();
        term();
        gen(OPR,3);
        while(sym==plussym||sym==minussym){
            if(sym==plussym){
                getsym();
                term();
                gen(OPR,2);
            }
            else{
                getsym();
                term();
                gen(OPR,3);
            }
        }
    }
    else{
        term();
        while(sym==plussym||sym==minussym){
            if(sym==plussym){
                getsym();
                term();
                gen(OPR,2);
            }
            else{
                getsym();
                term();
                gen(OPR,3);
            }
        }
    }
    
}

/*
* 处理条件句
*/
void condition(){
    expression();
    if(sym==eqlsym){
        getsym();
        expression();
        gen(OPR,6);
    }
    else if(sym==neqsym){
        getsym();
        expression();
        gen(OPR,7);
    }
    else if(sym==ltsym){
        getsym();
        expression();
        gen(OPR,8);
    }
    else if(sym==leqsym){
        getsym();
        expression();
        gen(OPR,9);
    }
    else if(sym==gtsym){
        getsym();
        expression();
        gen(OPR,10);
    }
    else if(sym==geqsym){
        getsym();
        expression();
        gen(OPR,11);
    }
}

/*
* 处理语句
*/
void statement(){
    while(sym!=endsym){
        if(sym==identsym){
            int t=findintable(id);
            if(t!=-1){
                if(table[t].kind==constant) error(13);
                else if(table[t].kind==procedure) error(14);
                else{
                    getsym();
                    if(sym==becomesym){
                        getsym();
                        expression();
                        if(sym==semicolonsym){
                            gen(STO,table[t].adr);
                            getsym();
                        }
                        else error(0);
                    }
                    else error(5);
                }
            }
            else error(12);
        }
        else if(sym==whilesym){
            getsym();
            int t1=pcnum;
            if(sym==lparensym){
                getsym();
                condition();
                gen(JPC,0);
                int t2=pcnum-1;
                if(sym==rparensym){
                    getsym();
                    if(sym==beginsym){
                        getsym();
                        statement();
                        if(sym==endsym){
                            gen(JMP,t1);
                            Pcode[t2].a=pcnum;
                            getsym();
                        }
                        else error(15);
                    }
                    else error(10);
                }
                else error(9);
            }
            else error(8);
        }
        else if(sym==switchsym){
            getsym();
            if(sym==lparensym){
                getsym();
                if(sym!=rparensym){
                    expression();
                    if(sym==rparensym){
                        getsym();
                        if(sym==beginsym){
                            getsym();
                            int t=-1;
                            vector<int>Re;
                            while(sym==casesym){
                                getsym();
                                if(sym==numbersym){
                                    if(t!=-1) Pcode[t].a=pcnum;
                                    gen(OPR,15);
                                    gen(LIT,number);
                                    gen(OPR,6);
                                    gen(JPC,0);
                                    t=pcnum-1;
                                    getsym();
                                    if(sym==beginsym){
                                        getsym();
                                        statement();
                                        gen(JMP,0);
                                        Re.push_back(pcnum-1);
                                        if(sym==endsym) getsym();
                                        else error(15);
                                    }
                                    else error(10);
                                }
                                else if(sym==identsym){
                                    int ind=findintable(id);
                                    if(ind!=-1){
                                        if(table[ind].kind==constant){
                                            if(t!=-1) Pcode[t].a=pcnum;
                                            gen(OPR,15);
                                            gen(LIT,table[ind].val);
                                            gen(OPR,6);
                                            gen(JPC,0);
                                            t=pcnum-1;
                                            getsym();
                                            if(sym==beginsym){
                                                getsym();
                                                statement();
                                                gen(JMP,0);
                                                Re.push_back(pcnum-1);
                                                if(sym==endsym) getsym();
                                                else error(15);
                                            }
                                            else error(10);
                                        }
                                        else error(6);
                                    }
                                    else error(6);
                                }
                                else error(6);
                            }
                            if(sym==endsym){
                                Pcode[t].a=pcnum;
                                for(int i=0;i<Re.size();i++) Pcode[Re[i]].a=pcnum;
                                gen(OPR,14);
                                getsym();
                            }
                            else error(15);
                        }
                        else error(10);
                    }
                    else error(9);
                }
                else error(18);
            }
            else error(8);
        }
        else if(sym==readsym){
            getsym();
            gen(OPR,12);
            if(sym==identsym){
                int t=findintable(id);
                if(t!=-1){
                    if(table[t].kind==variable){
                        gen(STO,table[t].adr);
                        getsym();
                        if(sym==semicolonsym)getsym();
                        else error(7);
                    }
                    else error(16);
                }
                else error(12);
            }
            else error(16);
        }
        else if(sym==writesym){
            getsym();
            expression();
            if(sym==semicolonsym){
                gen(OPR,13);
                getsym();
            }
        }
        else if(sym==returnsym){
            getsym();
            expression();
            if(sym==semicolonsym){
                gen(OPR,0);
                getsym();
            }
        }
        else if(sym==ifsym){
            getsym();
            if(sym==lparensym){
                getsym();
                condition();
                gen(JPC,0);
                int t=pcnum-1;
                if(sym==rparensym){
                    getsym();
                    if(sym==beginsym){
                        getsym();
                        statement();
                        if(sym==endsym){
                            Pcode[t].a=pcnum;
                            getsym();
                        }
                        else error(15);
                    }
                    else error(10);
                }
                else error(9);
            }
            else error(8);
        }
        else error(1000);
    }
}

void gen(fct kind,int a){
    Pcode[pcnum].kind=kind;
    Pcode[pcnum].a=a;
    pcnum++;
    ppcode();
}

/*
* 处理函数体
*/
void block(){
    lvarnum=0;
    while(sym==intsym){
        getsym();
        intdeclaration();
        if(sym==semicolonsym) getsym();
        else error(0);
    }
    renter();
    if(proname=="main") Pcode[0].a=pcnum;
    gen(INT,parnum+lvarnum);
    statement();
    if(sym==endsym){
        gen(OPR,0);
        getsym();
        
    }
    else error(15);
}

/*
* 处理函数声明
*/
void proceduredeclaration(){
    parnum=0;
    if(sym==identsym){
        if(word.count(id)==0){
            if(isvaliddeclaration(procedure)){
                proname=id;
                enter(procedure);
                getsym();
                if(sym==lparensym){
                    getsym();
                    if(sym!=rparensym){
                        parnum=0;
                        parameterdeclaration();
                        if(sym==rparensym){
                            getsym();
                            if(sym==beginsym){
                                getsym();
                                block();
                            }
                            else error(10);
                        }
                        else error(9);
                    }
                    else{
                        getsym();
                        if(sym==beginsym){
                            getsym();
                            block();
                            getsym();
                        }
                        else error(10);
                    }
                }
                else error(8);
            }
            else error(4);
        }
        else error(3);
    }
    else error(11);
}

/*
* 编译器主函数
*/
void compiler(){
    init();
    codein.open("code.txt",ios::in);
    if(!codein.is_open()){
        cout<<"Can't open the code.txt"<<endl;
        return;
    }
    while(getline(codein,linecode)) code.push_back(linecode+'\n');
    if(code.size()==0){
        cout<<"The code.txt is empty"<<endl;
        codein.close();
        return;
    }
    errout.open("error.txt",ios::out);
    if(!errout.is_open()){
        cout<<"Can't open the error.txt"<<endl;
        return;
    }
    linecode=code[linenum];
    Pcode[pcnum++].kind=JMP;
    getsym();
    while(sym!=nulsym){
        if(sym==constsym){
            getsym();
            if(sym==intsym) constdeclaration();
            else error(2);
        }
        else if(sym==intsym){
            getsym();
            proceduredeclaration();
        } 
    }
}

/*
* 解释器
*/
void interpret(){
    int pcindex=0;
    int p=2;
    int b=1;
    dastack[1]=0;           
    while(b!=0){
        // int fff;
        // cin>>fff;
        // cout<<b<<" "<<p<<endl;
        // pdastack(p);
        fct t=Pcode[pcindex].kind;
        int a=Pcode[pcindex].a;
        // cout<<t<<" "<<a<<endl;
        pcindex++;
        if(t==INT){
            p+=a;
        }
        else if(t==JMP){
            pcindex=a;
        }
        else if(t==JPC){
            if(dastack[p--]==0) pcindex=a;
        }
        else if(t==LIT){
            dastack[++p]=a;
        }
        else if(t==LOD){
            dastack[++p]=dastack[b+a+1];
        }
        else if(t==STO){
            dastack[b+a+1]=dastack[p--];
        }
        else if(t==CAL){
            dastack[++p]=b;
            b=p;
            dastack[++p]=pcindex;
            pcindex=a;
        }
        else if(t==STP){
            for(int i=0;i<a;i++){
                dastack[p+2-i]=dastack[p-i];
            }
            p=p-a;
        }
        else if(t==OPR){
            if(a==0){
                pcindex=dastack[b+1];
                int tmp=dastack[b];
                dastack[b]=dastack[p];
                p=b;
                b=tmp;
            }
            else if(a==1){
                dastack[p-1]=dastack[p-1]%dastack[p];
                p--;
            }
            else if(a==2){
                dastack[p-1]=dastack[p-1]+dastack[p];
                p--;
            }
            else if(a==3){
                dastack[p-1]=dastack[p-1]-dastack[p];
                p--;
            }
            else if(a==4){
                dastack[p-1]=dastack[p-1]*dastack[p];
                p--;
            }
            else if(a==5){
                if(dastack[p]==0){
                    cout<<"除0错误"<<endl;
                    dastack[p-1]=0;
                }
                else{
                    dastack[p-1]=dastack[p-1]/dastack[p];
                }
                p--;
            }
            else if(a==6){
                dastack[p-1]=(dastack[p-1]==dastack[p]);
                p--;
            }
            else if(a==7){
                dastack[p-1]=(dastack[p-1]!=dastack[p]);
                p--;
            }
            else if(a==8){
                dastack[p-1]=(dastack[p-1]<dastack[p]);
                p--;
            }
            else if(a==9){
                dastack[p-1]=(dastack[p-1]<=dastack[p]);
                p--;
            }
            else if(a==10){
                dastack[p-1]=(dastack[p-1]>dastack[p]);
                p--;
            }
            else if(a==11){
                dastack[p-1]=(dastack[p-1]>=dastack[p]);
                p--;
            }
            else if(a==12){
                int tmp;
                cin>>tmp;
                dastack[++p]=tmp;
            }
            else if(a==13){
                cout<<dastack[p--]<<endl;
            }
            else if(a==14) p--;
            else if(a==15){
                p++;
                dastack[p]=dastack[p-1];
            }
        }
    }
}

int main(){
    system("chcp 65001");
    compiler();
    cout<<"compiler success"<<endl;
    interpret();
    return 0;
}

void ppcode(){
    return;
    cout<<"---------Pcode----------"<<endl;
    for(int i=0;i<pcnum;i++){
        cout<<i<<" ";
        switch (Pcode[i].kind)
        {
        case INT:
            cout<<"INT"<<" "<<Pcode[i].a<<endl;
            break;
        case JMP:
            cout<<"JMP"<<" "<<Pcode[i].a<<endl;
            break;
        case JPC:
            cout<<"JPC"<<" "<<Pcode[i].a<<endl;
            break;
        case LIT:
            cout<<"LIT"<<" "<<Pcode[i].a<<endl;
            break;
        case LOD:
            cout<<"LOD"<<" "<<Pcode[i].a<<endl;
            break;
        case STO:
            cout<<"STO"<<" "<<Pcode[i].a<<endl;
            break;
        case CAL:
            cout<<"CAL"<<" "<<Pcode[i].a<<endl;
            break;
        case STP:
            cout<<"STP"<<" "<<Pcode[i].a<<endl;
            break;
        case OPR:
            cout<<"OPR"<<" "<<Pcode[i].a<<endl;
            break;
        default:
            break;
        }
    }
}

void ptable(){
    return;
    cout<<"---------Table----------"<<endl;
    for(int i=0;i<txind;i++){
        switch (table[i].kind)
        {
        case constant:
            cout<<table[i].name<<" "<<"constant"<<" "<<table[i].val<<endl;
            break;
        case variable:
            cout<<table[i].name<<" "<<"variable"<<" "<<table[i].adr<<endl;
            break;
        case procedure:
            cout<<table[i].name<<" "<<"procedure"<<" "<<table[i].adr<<endl;
            break;
        default:
            break;
        }
    }
}
void pdastack(int t){
    for(int i=0;i<=t;i++){
        cout<<dastack[i]<<endl;
    }
}
